package net.sureon.biz;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sureon.common.cache.LRUCache;
import net.sureon.common.exception.ExceptionKeys;
import net.sureon.common.exception.SureonException;
import net.sureon.dao.BalanceOperation;
import net.sureon.dao.Company;
import net.sureon.dao.CompanyDAO;
import net.sureon.dao.ConsumeRecord;
import net.sureon.dao.DailyTimingStatistic;
import net.sureon.dao.RealTimeConsume;

public class CompanyMgrImpl implements CompanyMgr {

	private CompanyDAO companyDAO;
	private LRUCache cache;

	public CompanyMgrImpl() {
		cache = new LRUCache(128);
	}

	/**
	 * @return the companyDAO
	 */
	public CompanyDAO getCompanyDAO() {
		return companyDAO;
	}

	/**
	 * @param companyDAO
	 *            the companyDAO to set
	 */
	public void setCompanyDAO(CompanyDAO companyDAO) {
		this.companyDAO = companyDAO;
	}

	public CompanyBO getCompany(long companyID) throws SureonException {
		Object o = cache.get(companyID);
		if (o == null) {
			Company c = getCompanyDAO().getCompany(companyID);
			if (c == null) {
				throw new SureonException(ExceptionKeys.COMPANY_NOT_FOUND)
						.appendExtraInfo("companyID", companyID);
			}
			o = new CompanyBO(c);
			cache.put(companyID, o);
		}
		return (CompanyBO) o;
	}

	public CompanyBO getCompany(String siteURL) throws SureonException {
		Object o = cache.get(siteURL);
		if (o == null) {
			Company c = getCompanyDAO().getCompanyBySiteURL(siteURL);
			if (c == null) {
				throw new SureonException(ExceptionKeys.COMPANY_NOT_FOUND)
						.appendExtraInfo("siteURL", siteURL);
			}
			o = new CompanyBO(getCompanyDAO().getCompanyBySiteURL(siteURL));
			cache.put(siteURL, o);
		}
		return (CompanyBO) o;
	}

	public List<CompanyBO> getAllCompanies() throws SureonException {
		List<Company> list = companyDAO.getAllCompanies();
		List<CompanyBO> returnList = new ArrayList<CompanyBO>();
		for (Company c : list) {
			CompanyBO bo = new CompanyBO(c);
			cache.put(c.getCompanyID(), bo);
			cache.put(c.getSiteURL(), bo);
			returnList.add(bo);
		}
		return returnList;
	}

	public long insertCompany(CompanyBO company) throws SureonException {
		String siteURL = company.getCompanyVO().getSiteURL();
		long companyID = getCompanyDAO().insertCompany(company.getCompanyVO());
		cache.put(siteURL, company);
		cache.put(companyID, company);
		return companyID;
	}

	public int updateCompany(CompanyBO company) throws SureonException {
		String siteURL = company.getCompanyVO().getSiteURL();
		int affectedRows = getCompanyDAO()
				.updateCompany(company.getCompanyVO());

		cache.put(siteURL, company);
		cache.put(company.getCompanyVO().getCompanyID(), company);
		return affectedRows;
	}

	public CompanyConfigBO getCompanyConfig(long companyID)
			throws SureonException {
		Object o = cache.get(companyID + "_CONFIG");
		if (o == null) {
			List config = companyDAO.getCompanyConfig(companyID);
			o = new CompanyConfigBO(config);
			cache.put(companyID + "_CONFIG", o);
		}
		return (CompanyConfigBO) o;
	}

	public int mergeCompanyConfig(long companyID, String key, String value)
			throws SureonException {
		// TODO Auto-generated method stub
		Map oneConfig = new HashMap();
		oneConfig.put(CompanyConfigBO.MAP_KEY_ID, companyID);
		oneConfig.put(CompanyConfigBO.MAP_KEY_KEY, key);
		oneConfig.put(CompanyConfigBO.MAP_KEY_VALUE, value);

		CompanyConfigBO config = getCompanyConfig(companyID);

		int affectedRows = 0;
		if (config.isItemDefined(key)) {
			affectedRows = companyDAO.updateCompanyConfig(oneConfig);
		} else {
			companyDAO.insertCompanyConfig(oneConfig);
		}
		cache.remove(companyID + "_CONFIG");
		return affectedRows;
	}

	public List<DailyTimingStatistic> getDailyTimingStatisticByCompany(
			long companyID) {
		return companyDAO.getDailyTimingStatisticByCompany(companyID);
	}

	public List<DailyTimingStatistic> getDailyTimingStatisticByCompany(
			long companyID, Date startDate, Date endDate) {
		return companyDAO.getDailyTimingStatisticByCompany(companyID,
				startDate, endDate);
	}

	public float getCompanyBalance(long companyID) {
		return companyDAO.getCompanyBalance(companyID);
	}

	public Date getLastestConsume(long companyID) {
		return companyDAO.getLastestConsume(companyID);
	}

	public List<BalanceOperation> getRecentTenBalanceOperation(long companyID) {
		return companyDAO.getRecentTenBalanceOperation(companyID);
	}

	public List<ConsumeRecord> getRecentTenConsumeRecord(long companyID) {
		return companyDAO.getRecentTenConsumeRecord(companyID);
	}

	public void insertBalanceOperation(BalanceOperation operation) {
		companyDAO.insertBalanceOperation(operation);
	}

	public void insertConsumeRecord(ConsumeRecord record) {
		companyDAO.insertConsumeRecord(record);
	}

	public RealTimeConsume getCompanyConsumeStatus(long companyID, Date theMonth) {
		return companyDAO.getCompanyConsumeStatus(companyID, theMonth);
	}

	public List<CompanyBO> getCustomerByStatus(String companyStatus) {
		List<Company> list = companyDAO.getCustomerByStatus(companyStatus);
		List<CompanyBO> companyBOs = new ArrayList<CompanyBO>();
		CompanyBO companyBO = null;
		if(list != null && list.size() != 0) {
			for(Company company : list) {
				companyBOs.add(new CompanyBO(company));
			}
			return companyBOs;
		}
		return null;
	}

	public List<ConsumeRecord> getAllCompanyRecentTenConsumeRecord() {
		return companyDAO.getAllCompanyRecentTenConsumeRecord();
	}

	public List<ConsumeRecord> getConsumeRecordBySiteURL(String siteURL) throws SureonException {
		CompanyBO company = null;
		try {
			company = getCompany(siteURL);
		}catch(SureonException e) {
			throw new SureonException("company_not_found");
		}
		long companyID = 0;
		if(company != null) {
			companyID = company.getCompanyID();
		}
		if(companyID > 0) {
			return getRecentTenConsumeRecord(companyID);
		}
		return null;
	}

	public List<ConsumeRecord> getRecentTenConsumeRecordInRangeMonth(
			Date startMonth, Date endMonth) {
		return companyDAO.getRecentTenConsumeRecordInRangeMonth(startMonth, endMonth);
	}

	public List<ConsumeRecord> getConsumeRecordBySiteURLConsumeMonth(
			Date startMonth, Date endMonth, long companyID) {
		return companyDAO.getConsumeRecordBySiteURLConsumeMonth(startMonth, endMonth, companyID);
	}
	
	public List<BalanceOperation> getAllCompanyBalanceOperation() {
		return companyDAO.getAllCompanyBalanceOperation();
	}
	
	public List<BalanceOperation> getBalanceOperationByOperationDate(Date startDate, Date endDate) {
		return companyDAO.getBalanceOperationByOperationDate(startDate, endDate);
	}
	
	public List<BalanceOperation> getBalanceOperationByCompanyIDAndOperationDate(long companyID, Date startDate, Date endDate) {
		return companyDAO.getBalanceOperationByCompanyIDAndOperationDate(companyID, startDate, endDate);
	}
}
